/*
 * Copyright (c) 2010 Vadim Zhukov <persgray@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */


#include "common.h"


#include <err.h>
#include <stdint.h>
#include <stdio.h>

#if defined(HAS_SYSINFO)
#include <sys/sysinfo.h>
#include <linux/kernel.h>
#elif !defined(__linux__)
#include <sys/param.h>
#include <sys/sysctl.h>
/* FreeBSD-specific, for struct loadavg */
#include <sys/user.h>
#endif

#include "logmsg.h"
#include "sensor.h"


int
sensor_loadavg_get(struct wsensor *s, struct log_msg *m) {
#if defined(HAS_SYSINFO)
	struct sysinfo	 si;

	if (sysinfo(&si) == -1)
		return -1;
	if (asprintf(&m->text, "%.02f %.02f %.02f",
	    ((double)si.loads[0]) / ((double)(1 << SI_LOAD_SHIFT)),
	    ((double)si.loads[1]) / ((double)(1 << SI_LOAD_SHIFT)),
	    ((double)si.loads[2]) / ((double)(1 << SI_LOAD_SHIFT))) == -1) {
		m->text = NULL;
		return -1;
	}
	return 0;

#elif !defined(__linux__)
	struct loadavg	la;
	size_t		len;
	int		mib[2] = { CTL_VM, VM_LOADAVG };

	len = sizeof(struct loadavg);
	if (sysctl(mib, nitems(mib), &la, &len, NULL, 0) == -1)
		return -1;

	if (asprintf(&m->text, "%.02f %.02f %.02f",
	    ((double)la.ldavg[0]) / la.fscale,
	    ((double)la.ldavg[1]) / la.fscale,
	    ((double)la.ldavg[2]) / la.fscale) == -1) {
		m->text = NULL;
		return -1;
	}
	
	return 0;

#else
	ssize_t	n;
	int	fd, i;
	char	buf[32], *p;

	fd = open("/proc/loadavg", O_RDONLY, 0);
	if (fd == -1)
		goto err;
	n = read(fd, buf, sizeof(buf));
	if (n <= 0) {
		if (n == 0)
			errno = EIO;
		goto err;
	}
	(void)close(fd);
	fd = -1;
	buf[nitems(buf) - 1] = '\0';
	for (p = buf, i = 0; p != NULL && i < 3; p = strchr(p, ' '), i++);
	if (i != 3) {
		errno = ERANGE;
		goto err;
	}
	if (p == NULL)
		p = &buf[nitems(buf) - 1];
	m->text = malloc(p - buf + 1);
	if (m->text == NULL)
		goto err;
	memcpy(m->text, buf, p - buf);
	m->text[p - buf] = '\0';
	return 0;

err:
	DPRINTF(1, "sensor_loadavg_get");
	(void)close(fd);
	return -1;
#endif
}
